package com.system.oauthserver.config;


import com.system.commonutils.pojo.Role;
import com.system.oauthserver.service.RoleService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import java.util.*;

@Component
public class MyRoleHierarchyImpl  implements RoleHierarchy {

    @Autowired
    RoleService roleService;

    private static final Log logger = LogFactory.getLog(RoleHierarchyImpl.class);
    private Map<String, Set<GrantedAuthority>> rolesReachableInOneStepMap = null;
    private Map<String, Set<GrantedAuthority>> rolesReachableInOneOrMoreStepsMap = null;
    private List<Role> list;

    public MyRoleHierarchyImpl() {
    }

    public void loadRole() {

        list = roleService.selectRoleList();
        this.buildRolesReachableInOneStepMap();
        this.buildRolesReachableInOneOrMoreStepsMap();
    }


    @Override
    public Collection<GrantedAuthority> getReachableGrantedAuthorities(Collection<? extends GrantedAuthority> authorities) {
        if (authorities != null && !authorities.isEmpty()) {
            Set<GrantedAuthority> reachableRoles = new HashSet();
            Set<String> processedNames = new HashSet();
            Iterator var4 = authorities.iterator();
            while(true) {
                while(var4.hasNext()) {
                    GrantedAuthority authority = (GrantedAuthority)var4.next();
                    if (authority.getAuthority() == null) {
                        reachableRoles.add(authority);
                    } else if (processedNames.add(authority.getAuthority())) {
                        reachableRoles.add(authority);
                        Set<GrantedAuthority> lowerRoles = (Set)this.rolesReachableInOneOrMoreStepsMap.get(authority.getAuthority());
                        if (lowerRoles != null) {
                            Iterator var7 = lowerRoles.iterator();

                            while(var7.hasNext()) {
                                GrantedAuthority role = (GrantedAuthority)var7.next();
                                if (processedNames.add(role.getAuthority())) {
                                    reachableRoles.add(role);
                                }
                            }
                        }
                    }
                }

                if (logger.isDebugEnabled()) {
                    logger.debug("getReachableGrantedAuthorities() - From the roles " + authorities + " one can reach " + reachableRoles + " in zero or more steps.");
                }

                List<GrantedAuthority> reachableRoleList = new ArrayList(reachableRoles.size());
                reachableRoleList.addAll(reachableRoles);
                return reachableRoleList;
            }
        } else {
            return AuthorityUtils.NO_AUTHORITIES;
        }
    }

    private void buildRolesReachableInOneStepMap() {
        this.rolesReachableInOneStepMap = new HashMap();
        int total = list.size();
        for(int var3 = 0; var3 < total; ++var3) {
            Role role = list.get(var3);
            String name = role.getRole_name();
            Integer level = role.getLevel();
            for (int i=0;i<total;i++){
                Role role1 = list.get(i);
                if(role1.getLevel()==level+1){
                    if(rolesReachableInOneStepMap.containsKey(name)){
                        Set<GrantedAuthority> grantedAuthorities = rolesReachableInOneStepMap.get(name);
                        grantedAuthorities.add(new SimpleGrantedAuthority(role1.getRole_name()));
                    }else {
                        Set<GrantedAuthority> grantedAuthorities=new HashSet<>();
                        grantedAuthorities.add(new SimpleGrantedAuthority(role1.getRole_name()));
                        rolesReachableInOneStepMap.put(name,grantedAuthorities);
                    }
                }
            }
        }

    }

    private void buildRolesReachableInOneOrMoreStepsMap() {
        this.rolesReachableInOneOrMoreStepsMap = new HashMap();
        int total = list.size();
        for(int var3 = 0; var3 < total; ++var3) {
            Role role = list.get(var3);
            String name = role.getRole_name();
            Integer level = role.getLevel();
            for (int i=0;i<total;i++){
                Role role1 = list.get(i);
                if(role1.getLevel()>level){
                    if(rolesReachableInOneOrMoreStepsMap.containsKey(name)){
                        Set<GrantedAuthority> grantedAuthorities = rolesReachableInOneOrMoreStepsMap.get(name);
                        grantedAuthorities.add(new SimpleGrantedAuthority(role1.getRole_name()));
                    }else {
                        Set<GrantedAuthority> grantedAuthorities=new HashSet<>();
                        grantedAuthorities.add(new SimpleGrantedAuthority(role1.getRole_name()));
                        rolesReachableInOneOrMoreStepsMap.put(name,grantedAuthorities);
                    }
                }
            }
        }

    }
}
